// Copyright Epic Games, Inc. All Rights Reserved.

#include "UI/Weapons/SCircumferenceMarkerWidget.h"

#include "Engine/UserInterfaceSettings.h"
#include "Styling/SlateBrush.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(SCircumferenceMarkerWidget)

class FPaintArgs;
class FSlateRect;

/**
 * 构造函数
 */
SCircumferenceMarkerWidget::SCircumferenceMarkerWidget()
{
}

/**
 * 构建控件
 * @param InArgs Slate参数
 */
void SCircumferenceMarkerWidget::Construct(const FArguments& InArgs)
{
	MarkerBrush = InArgs._MarkerBrush; //设置标记画刷
	MarkerList = InArgs._MarkerList; //设置标记列表
	Radius = InArgs._Radius; //设置半径
	bColorAndOpacitySet = InArgs._ColorAndOpacity.IsSet(); //设置颜色和不透明度是否设置
	ColorAndOpacity = InArgs._ColorAndOpacity; //设置颜色和不透明度
}

/**
 * 获取标记的渲染变换
 * @param Marker 标记条目
 * @param BaseRadius 基础半径
 * @param HUDScale HUD缩放
 * @return 渲染变换
 */
FSlateRenderTransform SCircumferenceMarkerWidget::GetMarkerRenderTransform(const FCircumferenceMarkerEntry& Marker, const float BaseRadius, const float HUDScale) const
{
	// 确定用于角的半径
	float XRadius = BaseRadius; //X半径
	float YRadius = BaseRadius; //Y半径
	if (bReticleCornerOutsideSpreadRadius) //如果十字准星角在扩散半径外
	{
		XRadius += MarkerBrush->ImageSize.X * 0.5f; //调整X半径
		YRadius += MarkerBrush->ImageSize.X * 0.5f; //调整Y半径
	}

	// 获取此十字准星角的角度和方向
	const float LocalRotationRadians = FMath::DegreesToRadians(Marker.ImageRotationAngle); //本地旋转弧度
	const float PositionAngleRadians = FMath::DegreesToRadians(Marker.PositionAngle); //位置角度弧度

	// 首先围绕原点旋转角图像
	FSlateRenderTransform RotateAboutOrigin(Concatenate(FVector2D(-MarkerBrush->ImageSize.X * 0.5f, -MarkerBrush->ImageSize.Y * 0.5f), FQuat2D(LocalRotationRadians), FVector2D(MarkerBrush->ImageSize.X * 0.5f, MarkerBrush->ImageSize.Y * 0.5f))); //围绕原点旋转

	// 将旋转后的图像移动到扩散半径上的正确位置
	return TransformCast<FSlateRenderTransform>(Concatenate(RotateAboutOrigin, FVector2D(XRadius * FMath::Sin(PositionAngleRadians) * HUDScale, -YRadius * FMath::Cos(PositionAngleRadians) * HUDScale))); //连接变换
}

/**
 * 绘制控件
 * @param Args 绘制参数
 * @param AllottedGeometry 分配的几何信息
 * @param MyCullingRect 剔除矩形
 * @param OutDrawElements 绘制元素列表
 * @param LayerId 图层ID
 * @param InWidgetStyle 控件样式
 * @param bParentEnabled 父控件是否启用
 * @return 图层ID
 */
int32 SCircumferenceMarkerWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
	const bool bIsEnabled = ShouldBeEnabled(bParentEnabled); //是否启用
	const ESlateDrawEffect DrawEffects = bIsEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; //绘制效果
	const FVector2D LocalCenter = AllottedGeometry.GetLocalPositionAtCoordinates(FVector2D(0.5f, 0.5f)); //本地中心

	const bool bDrawMarkers = (MarkerList.Num() > 0) && (MarkerBrush != nullptr); //是否绘制标记

	if (bDrawMarkers == true) //如果需要绘制标记
	{
		const FLinearColor MarkerColor = bColorAndOpacitySet ?
			ColorAndOpacity.Get().GetColor(InWidgetStyle) : //获取设置的颜色
			(InWidgetStyle.GetColorAndOpacityTint() * MarkerBrush->GetTint(InWidgetStyle)); //使用画刷色调

		if (MarkerColor.A > KINDA_SMALL_NUMBER) //如果颜色Alpha大于小数值
		{
			const float BaseRadius = Radius.Get(); //基础半径
			const float ApplicationScale = GetDefault<UUserInterfaceSettings>()->ApplicationScale; //应用缩放
			for (const FCircumferenceMarkerEntry& Marker : MarkerList) //遍历标记列表
			{
				const FSlateRenderTransform MarkerTransform = GetMarkerRenderTransform(Marker, BaseRadius, ApplicationScale); //获取标记变换

				const FPaintGeometry Geometry(AllottedGeometry.ToPaintGeometry(MarkerBrush->ImageSize, FSlateLayoutTransform(LocalCenter - (MarkerBrush->ImageSize * 0.5f)), MarkerTransform, FVector2D(0.0f, 0.0f))); //绘制几何
				FSlateDrawElement::MakeBox(OutDrawElements, LayerId, Geometry, MarkerBrush, DrawEffects, MarkerColor); //绘制盒子
			}
		}
	}

	return LayerId; //返回图层ID
}

/**
 * 计算期望大小
 * @param LayoutScaleMultiplier 布局缩放乘数
 * @return 期望大小
 */
FVector2D SCircumferenceMarkerWidget::ComputeDesiredSize(float) const
{
	check(MarkerBrush); //检查标记画刷
	const float SampledRadius = Radius.Get(); //采样半径
	return FVector2D((MarkerBrush->ImageSize.X + SampledRadius) * 2.0f, (MarkerBrush->ImageSize.Y + SampledRadius) * 2.0f); //返回期望大小
}

/**
 * 设置半径
 * @param NewRadius 新的半径值
 */
void SCircumferenceMarkerWidget::SetRadius(float NewRadius)
{
	if (Radius.IsBound() || (Radius.Get() != NewRadius)) //如果半径被绑定或值改变
	{
		Radius = NewRadius; //设置新半径
		Invalidate(EInvalidateWidgetReason::Layout); //使布局无效
	}
}

/**
 * 设置标记列表
 * @param NewMarkerList 新的标记列表
 */
void SCircumferenceMarkerWidget::SetMarkerList(TArray<FCircumferenceMarkerEntry>& NewMarkerList)
{
	MarkerList = NewMarkerList; //设置标记列表
}